package redora.configuration.rdo.service;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import redora.service.BusinessRuleViolation;
import redora.configuration.rdo.model.RedoraTrash;
import redora.exceptions.PersistException;
import redora.exceptions.QueryException;
import redora.exceptions.RedoraException;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

import static redora.api.fetch.Page.ALL_LIST;
import static redora.configuration.rdo.sql.RedoraTrashSQL.FIND_BY_NAME_AND_ID;

/**
 * Redora provides trash/undo functionality by adding the trash=true tag to the
 * object model. This service is the interface in maintaining your trash. The
 * object specific services also provide trash/undo functions.
 *
 * @see RedoraTrash
 * @author Nanjing RedOrange (www.red-orange.cn)
 */
public class TrashService {

    /**
     * Create a new record in the RedoraTrash table. You still have to set
     * roDeleted to true in the trashed object.
     * 
     * @param undoHash
     *            (Optional) When null, RedoraTrash will calculate a new hash.
     * @param objectId
     *            (Mandatory) Id of the trashed object
     * @param objectName
     *            (Mandatory) Name of the object
     * @throws RedoraException
     *             When a business rule is violated an exception is thrown
     *             because this should be unexpected.
     */
    public static void trash(@Nullable String undoHash, @NotNull Long objectId, @NotNull String objectName) throws RedoraException {
        RedoraTrash trash = new RedoraTrash();
        if (undoHash != null) {
            trash.setUndoHash(undoHash);
        }
        trash.setObjectId(objectId);
        trash.setObjectName(objectName);
        RedoraTrashService trashService = ServiceFactory.redoraTrashService();
        Set<BusinessRuleViolation> ret = trashService.persist(trash);
        ServiceFactory.close(trashService);
        for (BusinessRuleViolation violation : ret) {
            System.out.println(violation.getField().name());
        }
        if (!ret.isEmpty()) {
            throw new PersistException("Unexpected business rule violation(s). " + ret.size()
                    + " rules have been violated, the first rule is "
                    + ret.iterator().next().getBusinessRuleId());
        }
    }

    /**
     * Deletes the RedoraTrash. It will NOT delete the associated trashed
     * records.
     * 
     * @param objectId
     *            (Mandatory)
     * @param objectName
     *            (Mandatory)
     * @throws PersistException
     *             When a business rule is violated an exception is thrown
     *             because this should be unexpected.
     */
    public static void deleteTrash(@NotNull Long objectId, @NotNull String objectName) throws RedoraException {
        List<Object> params = new ArrayList<Object>();
        params.add(objectId);
        params.add(objectName);
        RedoraTrashService trashService = ServiceFactory.redoraTrashService();
        List<RedoraTrash> trashList = trashService.find(FIND_BY_NAME_AND_ID, params, ALL_LIST);
        if (trashList.size() != 1) {
            throw new QueryException("I expected to find one trashed record, but i found: "
                    + trashList.size());
        }

        Set<BusinessRuleViolation> ret = trashService.delete(trashList.iterator().next());
        ServiceFactory.close(trashService);
        if (!ret.isEmpty()) {
            throw new PersistException("Unexpected business rule violation(s). " + ret.size()
                    + " rules have been violated, the first rule is "
                    + ret.iterator().next().getBusinessRuleId());
        }
    }
}
